package com.psq.core.common.utils

import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import com.psq.core.common.model.BaseViewModel
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

inline fun AppCompatActivity.launch(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    lifecycleScope.launch(coroutineContext) {
        block()
    }
}

fun <T> AppCompatActivity.async(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return lifecycleScope.async(coroutineContext) {
        block()
    }
}

inline fun Fragment.launch(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    lifecycleScope.launch(coroutineContext) {
        block()
    }
}

fun <T> Fragment.async(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return lifecycleScope.async(coroutineContext) {
        block()
    }
}

inline fun ViewModel.launch(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    viewModelScope.launch(coroutineContext) {
        block()
    }
}

fun <T> ViewModel.async(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    return viewModelScope.async(coroutineContext) {
        block()
    }
}

fun BaseViewModel.tryLaunch(
    tryBlock: suspend CoroutineScope.() -> Unit,
    catchBlock: suspend CoroutineScope.() -> Unit = {},
    finallyBlock: suspend CoroutineScope.() -> Unit = {},
    coroutineContext: CoroutineContext = EmptyCoroutineContext
) {
    viewModelScope.launch(coroutineContext) {
        try {
            tryBlock()
        } catch (e: Exception) {
            if (e is CancellationException) throw e
            else {
                exception.value = e
                catchBlock()
            }
        } finally {
            finallyBlock()
        }
    }
}


inline fun View.launch(
    coroutineContext: CoroutineContext = EmptyCoroutineContext,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    (context as AppCompatActivity).launch(coroutineContext, block)
}

inline fun AppCompatActivity.launchRepeatOnLifecycle(
    state: Lifecycle.State = Lifecycle.State.STARTED,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    launch {
        lifecycle.repeatOnLifecycle(state) {
            block()
        }
    }
}

inline fun Fragment.launchRepeatOnLifecycle(
    state: Lifecycle.State = Lifecycle.State.STARTED,
    crossinline block: suspend CoroutineScope.() -> Unit
) {
    launch {
        lifecycle.repeatOnLifecycle(state) {
            block()
        }
    }
}


